package spring.cloud.tasks.log;

import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;


public class LoggerFactory {

    public static final String CONFIGURATION_FILE_PATH = "spring.cloud.tasks.log/";//相对项目jar根目录的路径
    //
    public static final Properties PROPERTIES = new Properties();
    public static final String PROPERTIES_PREFIX = "spring.cloud.tasks.log.";
    public static final String LOG_PATH_KEY = "log.path";
    //
    private static final Map<String, NameSpaceLoggerContext> MAP = new ConcurrentHashMap<>();
    //
    public static URL NAMESPACE_LOGBACK_XML_URL = null;

    static {
        //检查logback类库是否存在
        if (!isSupportedLogback(Thread.currentThread().getContextClassLoader())) {
            throw new IllegalStateException("请先加入logback类库");
        }
        //获取namespace.logback.xml
        URL url = LoggerFactory.class.getClassLoader().getResource(CONFIGURATION_FILE_PATH + "namespace.logback.xml");
        LoggerFactory.NAMESPACE_LOGBACK_XML_URL = url;
        //获取namespace.logback.properties
        Properties properties = new Properties();
        InputStream inputStream = null;
        try {
            inputStream = LoggerFactory.class.getClassLoader().getResourceAsStream(CONFIGURATION_FILE_PATH + "namespace.logback.properties");
            properties.load(inputStream);
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            //前缀处理
            LoggerFactory.PROPERTIES.put(String.valueOf(entry.getKey()).replace(PROPERTIES_PREFIX, ""), String.valueOf(entry.getValue()));
        }
        //logPath处理
        String logPath = LoggerFactory.PROPERTIES.getProperty(LOG_PATH_KEY);
        if (logPath == null || "null".equals(logPath)) {
            logPath = System.getProperty("user.home") + File.separator + "logs";
        }
        //日志文件夹创建
        File file = new File(logPath);
        if (!file.exists()) {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            file.mkdirs();
        }
        LoggerFactory.PROPERTIES.setProperty(LOG_PATH_KEY, logPath);
    }

    /**
     * 需要排除logback之外的slf4j实现
     * <pre>
     * SLF4J: Class path contains multiple SLF4J bindings.
     * SLF4J: Found binding in [jar:file:/C:/Users/huihui/.m2/repository/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
     * SLF4J: Found binding in [jar:file:/C:/Users/huihui/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.17.1/log4j-slf4j-impl-2.17.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
     * SLF4J: Found binding in [jar:file:/C:/Users/huihui/.m2/repository/ch/qos/logback/logback-classic/1.2.0/logback-classic-1.2.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
     * SLF4J: Found binding in [jar:file:/C:/Users/huihui/.m2/repository/org/slf4j/slf4j-jcl/1.7.21/slf4j-jcl-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
     * </pre>
     */
    public static boolean isSupportedLogback(ClassLoader classLoader) {
        try {
            return classLoader.loadClass(ch.qos.logback.classic.LoggerContext.class.getName()) != null;
        } catch (ClassNotFoundException e) {
            return false;
        }
    }

    public static Logger getLogger(Class aClass) {
        NameSpace nameSpace = (NameSpace) aClass.getDeclaredAnnotation(NameSpace.class);
        if (nameSpace == null) {
            throw new NullPointerException("请先配置:" + NameSpaceAndProperties.class.getName() + "注解");
        }
        NameSpaceLoggerContext nameSpaceLoggerFactory = getNameSpaceLoggerContext(nameSpace.value());
        return nameSpaceLoggerFactory.getLogger(aClass);
    }

    private static NameSpaceLoggerContext getNameSpaceLoggerContext(String nameSpace) {
        if (!MAP.containsKey(nameSpace)) {
            init(nameSpace);
            return MAP.get(nameSpace);
        } else {
            return MAP.get(nameSpace);

        }
    }

    public static void init(String nameSpace) {
        if (MAP.containsKey(nameSpace)) {
            return;
        }
        synchronized (MAP) {
            if (MAP.containsKey(nameSpace)) {
                return;
            }
            doInit(nameSpace);
        }
    }

    static void doInit(String nameSpace) {
        NameSpaceAndProperties nameSpaceAndProperties = new NameSpaceAndProperties(nameSpace, LoggerFactory.PROPERTIES);
        NameSpaceLoggerContext nameSpaceLoggerContext = createNameSpaceLoggerContext(nameSpaceAndProperties);
        MAP.putIfAbsent(nameSpace, nameSpaceLoggerContext);
    }

    private static NameSpaceLoggerContext createNameSpaceLoggerContext(NameSpaceAndProperties nameSpaceAndProperties) {
        URL url = LoggerFactory.NAMESPACE_LOGBACK_XML_URL;
        return new NameSpaceLoggerContext(nameSpaceAndProperties.nameSpace, new LoggerContext(), LoggerFactory.PROPERTIES, url);
    }
}
